package org.egrit;

import java.awt.Point;
import java.awt.Rectangle;

/**
 *
 * @author michael
 */
public interface IGridBounds {

    /**
     * Tests if the bounds are empty.
     *
     * @return {@code true} if empty
     */
    boolean isEmpty();
    
    /**
     * Gets the width of the bounds in cells.
     *
     * @return width in cells
     */
    int getWidth();

    /**
     * Gets the height of the bounds in cells.
     *
     * @return height in cells
     */
    int getHeight();

    /**
     * Returns the area of these bounds as the number of grid cells.
     * 
     * @return area in grid cells
     */
    int getArea();

    /**
     * Creates and returns an iterator for all cell positions within the bounds.
     *
     * @return a new iterator
     */
    IGridIterator getIterator();

    /**
     * Gets the minimum cell position.
     *
     * @return minimum cell position
     */
    Point getMinCellPos();

    /**
     * Gets the maximum cell position.
     *
     * @return maximum cell position
     */
    Point getMaxCellPos();

    /**
     * Gets the X ordinate of the left-most cell(s).
     *
     * @return minimum cell X ordinate
     */
    int getMinGridX();

    /**
     * Gets the X ordinate of the right-most cell(s).
     *
     * @return maximum cell X ordinate
     */
    int getMaxGridX();

    /**
     * Gets the Y ordinate of the lower-most cell(s).
     *
     * @return minimum cell Y ordinate
     */
    int getMinGridY();

    /**
     * Gets the Y ordinate of the upper-most cell(s).
     *
     * @return maximum cell Y ordinate
     */
    int getMaxGridY();

    /**
     * Gets the outer bounding rectangle of this region.
     *
     * @return a copy of the outer bounding rectangle
     */
    Rectangle getOuterRect();

    /**
     * Tests whether these bounds contain another instance, ie. no portion of the
     * other instance extends beyond these bounds.
     *
     * @param other other bounds
     *
     * @return {@code true} if the other bounds are contained by these bounds
     */
    boolean contains(IGridBounds other);

    /**
     * Tests if the given cell is within these bounds.
     *
     * @param gridPos cell position
     *
     * @return {@code true} if the cell is within these bounds
     */
    boolean containsCell(Point gridPos);

    /**
     * Tests if the given cell is within these bounds.
     *
     * @param gridX cell X ordinate
     * @param gridY cell Y ordinate
     *
     * @return {@code true} if the cell is within these bounds
     */
    boolean containsCell(int gridX, int gridY);

    /**
     * Creates a new bounds object which is the intersection of this instance
     * and another.
     *
     * @param other bounds to intersect with
     *
     * @return the intersection (may be empty)
     */
    IGridBounds intersection(IGridBounds other);

    /**
     * Creates a new bounds object which is the intersection of this instance
     * and the given rectangle. The input rectangle is treated as the
     * outer limits of a grid region, as opposed to the included cell limits.
     * So, for example, the {@code Rectangle(x=0, y=0, width=10, height=20)}
     * includes the cell at {@code (x=9, y=19)} but not {@code (x=10, y=20)}.
     *
     * @param rect rectangle defining the outer limits of the grid region
     * @return the intersection (may be empty)
     */
    IGridBounds intersection(Rectangle rect);

    /**
     * Tests whether these bounds intersect with another instance.
     *
     * @param other other bounds
     *
     * @return {@code true} if the bounds intersect
     */
    boolean intersects(IGridBounds other);

}
